package com.cheer.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.URLUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cheer.common.Page;
import com.cheer.dao.OaLearnClassDao;
import com.cheer.dto.OaLearnClassAddDTO;
import com.cheer.dto.OaLearnClassUpdateDTO;
import com.cheer.entity.OaLearnClassEntity;
import com.cheer.enums.OaLearnClassTypeEnum;
import com.cheer.exception.ServiceException;
import com.cheer.service.OaLearnClassService;
import com.cheer.service.OaLearnEntryService;
import com.cheer.service.OaUserService;
import com.cheer.utils.ExcelsUtil;
import com.cheer.vo.OaLearnClassInfoVO;
import com.cheer.vo.OaLearnClassListVO;
import com.cheer.vo.SimpleObjectVO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service("oaLearnClassService")
@Slf4j
public class OaLearnClassServiceImpl extends ServiceImpl<OaLearnClassDao, OaLearnClassEntity> implements OaLearnClassService {

    @Autowired
    private OaLearnClassDao oaLearnClassDao;

    @Autowired
    private OaUserService oaUserService;

    @Autowired
    private OaLearnEntryService oaLearnEntryService;

    @Override
    public OaLearnClassEntity add(OaLearnClassAddDTO learnClassAddDTO) {
        String path;
        if (learnClassAddDTO.getPid() == null || learnClassAddDTO.getPid() == 0) {
            path = "0,";
        } else {
            OaLearnClassEntity learnClass = oaLearnClassDao.selectById(learnClassAddDTO.getPid());
            if (learnClass == null) {
                throw new ServiceException("上级单位不存在");
            }
            path = learnClass.getPath() + learnClassAddDTO.getPid() + ",";
        }

        OaLearnClassEntity learnClass = new OaLearnClassEntity()
                .setPid(learnClassAddDTO.getPid())
                .setName(learnClassAddDTO.getName())
                .setNum(learnClassAddDTO.getNum())
                .setPath(path)
                .setAddTime(String.valueOf(DateUtil.currentSeconds()));

        oaLearnClassDao.insert(learnClass);

        return learnClass;
    }

    @Override
    public List<SimpleObjectVO> sub(Integer id) {
        List<OaLearnClassEntity> learnClassList = oaLearnClassDao.selectListByPid(id);

        return learnClassList.stream()
                .map(oaLearnClassEntity -> new SimpleObjectVO()
                        .setId((long) oaLearnClassEntity.getId())
                        .setName(oaLearnClassEntity.getName()))
                .sorted((o1, o2) -> {
                    if (StringUtils.equals("其他", o1.getName())) {
                        return 1;
                    } else if (StringUtils.equals("其他", o2.getName())) {
                        return -1;
                    } else {
                        return (int) (o1.getId() - o2.getId());
                    }
                })
                .collect(Collectors.toList());
    }

    @Override
    public Page<OaLearnClassListVO> list(Integer pageNum, Integer pageSize, Integer id) {
        IPage<OaLearnClassEntity> page;
        if (id != null && id != 0) {
            OaLearnClassEntity learnClass = oaLearnClassDao.selectById(id);
            if (learnClass == null) {
                throw new ServiceException("单位不存在");
            }
        }

        if (id == null) {
            id = 0;
        }

        page = oaLearnClassDao.selectPageByPath(pageNum, pageSize, id);

        Set<String> idSet = new HashSet<>();
        page.getRecords()
                .forEach(learnClass -> {
                    String[] split = StringUtils.split(learnClass.getPath(), ",");
                    idSet.addAll(Lists.newArrayList(split));
                });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();
        map.put(0, "顶级");

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            List<OaLearnClassEntity> learnClassList = oaLearnClassDao.selectBatchIds(ids);
            learnClassList.forEach(learnClass -> {
                map.put(learnClass.getId(), learnClass.getName());
            });
        }

        List<OaLearnClassListVO> learnClassList = page.getRecords().stream()
                .map(learnClass -> {
                    OaLearnClassListVO learnClassListVO = new OaLearnClassListVO()
                            .setId(learnClass.getId())
                            .setName(learnClass.getName())
                            .setNum(learnClass.getNum())
                            .setPath(learnClass.getPath() + learnClass.getId() + ",");

                    String[] split = StringUtils.split(learnClass.getPath(), ",");
                    if (split.length == 1 && split[0].equals("0")) {
                        learnClassListVO.setPname("顶级");
                    } else {
                        List<String> pLearnClass = new ArrayList<>();
                        for (String str : split) {
                            if (!str.equals("0")) {
                                String pClass = map.get(Integer.valueOf(str));
                                if (pClass != null) {
                                    pLearnClass.add(pClass);
                                }
                            }
                        }
                        learnClassListVO.setPname(StringUtils.join(pLearnClass, "-"));
                    }

                    return learnClassListVO;
                })
                .collect(Collectors.toList());

        return new Page<>(page, learnClassList);
    }

    @Override
    public void delete(Integer id) {
        OaLearnClassEntity learnClass = oaLearnClassDao.selectOneByPid(id);
        if (learnClass != null) {
            throw new ServiceException("请先删除子单位");
        }

        oaLearnClassDao.deleteById(id);
    }

    @Override
    @Transactional
    public void update(OaLearnClassUpdateDTO learnClassUpdateDTO) {
        OaLearnClassEntity oldLearnClass = oaLearnClassDao.selectById(learnClassUpdateDTO.getId());
        if (oldLearnClass == null) {
            throw new ServiceException("单位不存在");
        }

        if (learnClassUpdateDTO.getPid() == null) {
            learnClassUpdateDTO.setPid(0);
        }

        if (learnClassUpdateDTO.getNum() == null) {
            learnClassUpdateDTO.setNum(0);
        }

        if (Objects.equals(learnClassUpdateDTO.getId(), learnClassUpdateDTO.getPid())) {
            throw new ServiceException("上级单位不能是自己");
        }

        if (!learnClassUpdateDTO.getIsAdmin()) {
            if (oldLearnClass.getPid() == 22 || oldLearnClass.getPid() == 7459 || oldLearnClass.getPid() == 17950) {
                if (!Objects.equals(oldLearnClass.getNum(), learnClassUpdateDTO.getNum())) {
                    throw new ServiceException("只有超级管理员能够修改该单位人数");
                }
            }
        }
        // 属于高校的话只能管理员修改人数
        Integer school = 3;
        Integer college = 2;
        if( school.equals(oldLearnClass.getType())  || college.equals(oldLearnClass.getType()) ){
            if (!Objects.equals(oldLearnClass.getNum(), learnClassUpdateDTO.getNum())) {
                if(learnClassUpdateDTO.getIsAdminId() == false){
                    throw new ServiceException("高校人数只有管理员才能修改");
                }
            }
        }

        String path;
        if (learnClassUpdateDTO.getPid() == 0) {
            path = "0,";
        } else {
            OaLearnClassEntity pLearnClass = oaLearnClassDao.selectById(learnClassUpdateDTO.getPid());
            if (pLearnClass == null) {
                throw new ServiceException("上级单位不存在");
            }

            String[] split = StringUtils.split(pLearnClass.getPath(), ",");
            for (String str : split) {
                if (Objects.equals(Integer.valueOf(str), learnClassUpdateDTO.getId())) {
                    throw new ServiceException("上级单位不能是自己的子单位");
                }
            }

            path = pLearnClass.getPath() + learnClassUpdateDTO.getPid() + ",";
        }

        OaLearnClassEntity learnClass = new OaLearnClassEntity()
                .setId(learnClassUpdateDTO.getId())
                .setPid(learnClassUpdateDTO.getPid())
                .setName(learnClassUpdateDTO.getName())
                .setNum(learnClassUpdateDTO.getNum())
                .setUpdataTime(String.valueOf(DateUtil.currentSeconds()))
                .setPath(path);

        oaLearnClassDao.updateById(learnClass);

        if (!StringUtils.equals(path, oldLearnClass.getPath())) {
            updateChild(learnClass.getId(), learnClass.getPath());
        }
    }

    private void updateChild(Integer id, String path) {
        String newPath = path + id + ",";

        oaUserService.updatePathByDepartment(id, newPath);

        oaLearnEntryService.updatePathByDepartment(id, newPath);

        List<OaLearnClassEntity> list = listByPid(id);
        if (CollectionUtils.isNotEmpty(list)) {
            List<Integer> ids = list.stream()
                    .map(OaLearnClassEntity::getId)
                    .collect(Collectors.toList());

            oaLearnClassDao.updatePathByIds(newPath, ids);

            for (Integer newId : ids) {
                updateChild(newId, newPath);
            }
        }
    }

    @Override
    public OaLearnClassInfoVO info(Integer id) {
        OaLearnClassEntity learnClass = oaLearnClassDao.selectById(id);
        if (learnClass == null) {
            throw new ServiceException("单位不存在");
        }

        OaLearnClassInfoVO learnClassInfoVO = new OaLearnClassInfoVO()
                .setId(learnClass.getId())
                .setName(learnClass.getName())
                .setNum(learnClass.getNum());

        String[] split = StringUtils.split(learnClass.getPath(), ",");
        List<Integer> path = new ArrayList<>();
        if (ArrayUtils.isNotEmpty(split)) {
            for (String str : split) {
                if (!StringUtils.equals("0", str)) {
                    path.add(Integer.valueOf(str));
                }
            }
        }
        learnClassInfoVO.setPath(path);

        return learnClassInfoVO;
    }

    @Override
    public IPage<OaLearnClassEntity> listByPid(Integer pageNum, Integer pageSize, Integer pid) {
        return oaLearnClassDao.selectPageByPid(pageNum, pageSize, pid);
    }

    @Override
    public List<OaLearnClassEntity> listByPid(Integer pid) {
        return oaLearnClassDao.selectListByPid(pid);
    }

    @Override
    public void download(Integer id, HttpServletResponse response) {
        List<OaLearnClassEntity> list;
        if (id != null && id != 0) {
            OaLearnClassEntity learnClass = oaLearnClassDao.selectById(id);
            if (learnClass == null) {
                throw new ServiceException("单位不存在");
            }

            String path = learnClass.getPath() + id + ",";

            list = oaLearnClassDao.selectListByPath(id, path);
        } else {
            list = oaLearnClassDao.selectList(Wrappers.emptyWrapper());
        }

        Set<String> idSet = new HashSet<>();
        list.forEach(learnClass -> {
            String[] split = StringUtils.split(learnClass.getPath(), ",");
            idSet.addAll(Lists.newArrayList(split));
        });
        idSet.remove("0");

        Map<Integer, String> map = new HashMap<>();
        map.put(0, "顶级");

        if (CollectionUtils.isNotEmpty(idSet)) {
            List<Integer> ids = idSet.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            List<OaLearnClassEntity> learnClassList = oaLearnClassDao.selectBatchIds(ids);
            learnClassList.forEach(learnClass -> {
                map.put(learnClass.getId(), learnClass.getName());
            });
        }

        List<OaLearnClassListVO> learnClassList = list.stream()
                .map(learnClass -> {
                    OaLearnClassListVO learnClassListVO = new OaLearnClassListVO()
                            .setId(learnClass.getId())
                            .setName(learnClass.getName())
                            .setNum(learnClass.getNum());

                    String[] split = StringUtils.split(learnClass.getPath(), ",");
                    if (split.length == 1 && split[0].equals("0")) {
                        learnClassListVO.setPname("顶级");
                    } else {
                        List<String> pLearnClass = new ArrayList<>();
                        for (String str : split) {
                            if (!str.equals("0")) {
                                String pClass = map.get(Integer.valueOf(str));
                                if (pClass != null) {
                                    pLearnClass.add(pClass);
                                }
                            }
                        }
                        learnClassListVO.setPname(StringUtils.join(pLearnClass, "-"));
                    }

                    return learnClassListVO;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> excelList = new ArrayList<>();
        Map<String, Object> header = new HashMap<>();
        header.put("sheetName", "报名表");
        excelList.add(header);

        for (OaLearnClassListVO learnClassListVO : learnClassList) {
            Map<String, Object> line = new HashMap<>();
            line.put("learnClass", learnClassListVO.getName());
            line.put("pname", learnClassListVO.getPname());
            line.put("number", learnClassListVO.getNum());
            excelList.add(line);
        }

        String[] columnNames = {"单位名称", "所属单位", "人数"};
        String[] keys = {"learnClass", "pname", "number"};

        response.setContentType("application/x-download");
        response.addHeader("Content-Disposition", "attachment;filename=单位表.xlsx;filename*=UTF-8''"
                + URLUtil.encode("单位表.xlsx"));
        try (SXSSFWorkbook xssfWorkbook = ExcelsUtil.ExcelSingleOutputStream(excelList, keys, columnNames)) {
            xssfWorkbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("下载异常");
        }
    }

    @Override
    public List<OaLearnClassEntity> listByIdAndPid(Integer pid) {
        return oaLearnClassDao.selectListByIdAndPid(pid);
    }

    @Override
    public List<OaLearnClassEntity> importLearnClass(Integer pid, MultipartFile file) {

        List<OaLearnClassEntity> lists = new ArrayList<>();
        XSSFWorkbook workBook;
        try {
            workBook = new XSSFWorkbook(file.getInputStream());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("导入异常");
        }

        XSSFSheet sheet = workBook.getSheetAt(0);

        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row != null) {

                OaLearnClassAddDTO learnClassAddDTO = new OaLearnClassAddDTO();
                learnClassAddDTO.setPid(pid);

                Cell cell = row.getCell(0);
                if (cell != null && StringUtils.isNotBlank(cell.getStringCellValue())) {
                    learnClassAddDTO.setName(cell.getStringCellValue());
                }

                cell = row.getCell(1);
                if (cell != null) {
                    learnClassAddDTO.setNum((int) cell.getNumericCellValue());
                }
                OaLearnClassEntity add = add(learnClassAddDTO);
                lists.add(add);
            }
        }
        return lists;
    }

    @Override
    public void importAll(MultipartFile file) {
        XSSFWorkbook workBook;
        try {
            workBook = new XSSFWorkbook(file.getInputStream());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("导入异常");
        }

        XSSFSheet sheet = workBook.getSheetAt(0);

        Set<Integer> learnClassIdSet = new HashSet<>();

        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                Cell cell = row.getCell(0);
                String learnClassName = "";
                if (cell != null) {
                    if (cell.getCellTypeEnum() == CellType.NUMERIC) {
                        learnClassName = StringUtils.stripToEmpty(String.valueOf(cell.getNumericCellValue()));
                    } else {
                        learnClassName = StringUtils.stripToEmpty(cell.getStringCellValue());
                    }
                }
                if (StringUtils.isBlank(learnClassName)) {
                    log.error("添加单位失败：第{}条数据，数据内容 {}", i, learnClassName);
                    continue;
                }

                cell = row.getCell(1);
                String parentLearnClass = "";
                if (cell != null) {
                    if (cell.getCellTypeEnum() == CellType.NUMERIC) {
                        parentLearnClass = StringUtils.stripToEmpty(String.valueOf(cell.getNumericCellValue()));
                    } else {
                        parentLearnClass = StringUtils.stripToEmpty(cell.getStringCellValue());
                    }
                }
                if (StringUtils.isBlank(parentLearnClass)) {
                    log.error("添加单位失败：第{}条数据，数据内容 {}", i, parentLearnClass);
                    continue;
                }

                StringBuilder path = new StringBuilder("0,");
                Integer pid = 0;

                String[] parentLearnClassArray = StringUtils.split(parentLearnClass, "-");
                boolean flag = false;
                for (String s : parentLearnClassArray) {
                    if (StringUtils.stripToEmpty(s).equals("顶级")) {
                        continue;
                    }
                    OaLearnClassEntity item = oaLearnClassDao.selectOne(new QueryWrapper<OaLearnClassEntity>()
                            .eq("name", StringUtils.stripToEmpty(s))
                            .eq("pid", pid)
                            .last("limit 1"));
                    if (item == null) {
                        flag = true;
                        break;
                    } else {
                        path.append(item.getId()).append(",");
                        pid = item.getId();
                    }
                }
                if (flag) {
                    log.error("添加单位失败：第{}条数据，数据内容 {}", i, learnClassName);
                    continue;
                }

                OaLearnClassEntity learnClassEntity = oaLearnClassDao.selectOne(new QueryWrapper<OaLearnClassEntity>()
                        .eq("name", learnClassName)
                        .eq("pid", pid)
                        .last("limit 1"));
                if (learnClassEntity == null) {
                    OaLearnClassEntity item = new OaLearnClassEntity()
                            .setName(learnClassName)
                            .setPid(pid)
                            .setPath(path.toString())
                            .setAddTime(String.valueOf(DateUtil.currentSeconds()));
                    oaLearnClassDao.insert(item);
                    learnClassIdSet.add(item.getId());
                } else {
                    learnClassIdSet.add(learnClassEntity.getId());
                }
            }

        }

        for (OaLearnClassEntity learnClassEntity : list()) {
            if (!learnClassIdSet.contains(learnClassEntity.getId())) {
                //log.info("删除单位：" + learnClassEntity.getId() + " " + learnClassEntity.getName());
                oaLearnClassDao.deleteById(learnClassEntity.getId());
            }
        }

    }

    @Override
    public List<OaLearnClassEntity> listSchool() {

        return oaLearnClassDao.listSchool();
    }

    @Override
    public List<OaLearnClassEntity> listSchool(Integer type) {

        return oaLearnClassDao.listSchool(type);
    }

    @Override
    public List<OaLearnClassEntity> listPrefecture() {
        QueryWrapper<OaLearnClassEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(OaLearnClassEntity::getType, OaLearnClassTypeEnum.PREFECTURE.getCode())
                .eq(OaLearnClassEntity::getIsDeleted, 0);
        List<OaLearnClassEntity> list = list(queryWrapper);
        return list;
    }

    @Override
    public String getOrgPathByPid(Integer pid) {
        String path = "0,";
        if(pid != 0){
            OaLearnClassEntity oaLearnClassEntity = getById(pid);
            if(oaLearnClassEntity == null){
                throw new ServiceException("未查询到当前指定机构");
            }
            path = oaLearnClassEntity.getPath();
        }
        return path;
    }

}